#pragma once

#include <AVUIItemStructList.h>
#include <AVUIRoutedEventHandlerInfo.h>
#include <AVUIStack.h>

namespace AVUI {

/// <summary> Represents the container for the route to be followed by a routed event. </summary>
class EventRoute
{
public:
#pragma region Public Methods

    /// <summary> Initializes an instance of the <see cref="T:System.Windows.EventRoute" /> class. </summary>
    /// <param name="routedEvent">The non-NULL event identifier to be associated with this event route.</param>
    EventRoute(RoutedEvent* pRoutedEvent);

    /// <summary> Adds the specified handler for the specified target to the route. </summary>
    /// <returns />
    /// <param name="target">Specifies the target object of which the handler is to be added to the route.</param>
    /// <param name="handler">Specifies the handler to be added to the route.</param>
    /// <param name="handledEventsToo">Indicates whether or not the listener detects events that have already been handled.</param>
    void Add(Object* pTarget, Delegate* pHandler, bool handledEventsToo);

    /// <summary> Do not use. Supports constructing event routes internally. </summary>
    /// <returns />
    Object* PeekBranchNode();

    /// <summary>Do not use. Supports constructing event routes internally.</summary>
    /// <returns />
    Object* PeekBranchSource();

    /// <summary> Do not use. Supports constructing event routes internally. </summary>
    /// <returns />
    TRefCountedPtr<Object> PopBranchNode();

    /// <summary> Do not use. Supports constructing event routes internally. </summary>
    /// <returns />
    /// <param name="node" />
    /// <param name="source" />
    void PushBranchNode(Object* pNode, Object* pSource);

#pragma endregion Public Methods

public:

#pragma region Internal Methods

    void AddSource(Object* pSource);
    void Clear();
    void InvokeHandlers(Object* pSource, RoutedEventArgs* pArgs);
    void ReInvokeHandlers(Object* pSource, RoutedEventArgs* pArgs);

#pragma endregion Internal Methods

#pragma region Internal Properties

    RoutedEvent* get_RoutedEvent() { return m_pRoutedEvent; }
    void set_RoutedEvent(RoutedEvent* pValue) { m_pRoutedEvent = pValue; }

#pragma endregion Internal Properties

private:

#pragma region Private Methods
 
    Object* GetBubbleSource(int index, int* pEndIndex);
    Object* GetTunnelSource(int index, int* pStartIndex);
    void InvokeHandlersImpl(Object* pSource, RoutedEventArgs* pArgs, bool reRaised);
 
#pragma region Private Methods

#pragma region Private Properties

    struct BranchNode
    {
        TRefCountedPtr<Object> Node;
        TRefCountedPtr<Object> Source;
    };

    TRefCountedPtr< Stack<BranchNode> > get_BranchNodeStack();

#pragma endregion Private Properties

#pragma region Private Fields

    struct RouteItem
    {
        RouteItem() { }
        RouteItem(Object* pTarget,  const RoutedEventHandlerInfo& routedEventHandlerInfo) : m_pTarget(pTarget), m_routedEventHandlerInfo(routedEventHandlerInfo) { }

        void InvokeHandler(RoutedEventArgs* pRoutedEventArgs)
        {
            m_routedEventHandlerInfo.InvokeHandler(m_pTarget, pRoutedEventArgs);
        }

        Object* get_Target() { return m_pTarget; }

    private:
        RoutedEventHandlerInfo m_routedEventHandlerInfo;
        TRefCountedPtr<Object> m_pTarget;
    };

    struct SourceItem
    {
        SourceItem() { }
        SourceItem(int startIndex, Object* pSource) : m_startIndex(startIndex), m_pSource(pSource) { }

        Object* get_Source() { return m_pSource; }
        int get_StartIndex() { return m_startIndex; }

    private:
        TRefCountedPtr<Object> m_pSource;
        int m_startIndex;        
    };

    TRefCountedPtr< Stack<BranchNode> > m_pBranchNodeStack;
    RoutedEvent* m_pRoutedEvent;
    ItemStructList<RouteItem> m_routeItemList;
    ItemStructList<SourceItem> m_sourceItemList;

#pragma endregion Private Fields

 


};

}; // namespace AVUI
